/**
 * 手写 promise
 * @param executor (resolve, reject) => {}
 * @constructor
 */
function Promise(executor) {

  const _this = this

  // 表示 promise 的状态
  this.PromiseState = 'pending'
  // 表示promise 的结果
  this.PromiseResult = null
  // 保存异步回调
  this.callback = {
    resolvedFn: [], rejectedFn: []
  }

  /**
   * 1、修改对象的状态 PromiseState
   * 2、设置对象结果值 PromiseResult
   * 3、执行器为异步任务时，调用成功的回调函数，回调函数异步执行
   * @param data
   */
  function resolve(data) {
    // 状态只能修改一次
    if (_this.PromiseState === 'pending') {
      // 1、修改对象的状态 PromiseState
      _this.PromiseState = 'fulfilled'
      // 2、设置对象结果值 PromiseResult
      _this.PromiseResult = data
      // 3、执行器为异步任务时，调用成功的回调函数，回调函数异步执行
      setTimeout(() => {
        _this.callback.resolvedFn.forEach(item => {
          item(data)
        })
      })
    }
  }

  /**
   * 1、修改对象的状态 PromiseState
   * 2、设置对象结果值 PromiseResult
   * 3、执行器为异步任务时，调用失败的回调函数，回调函数异步执行
   * @param data
   */
  function reject(data) {
    // 状态只能修改一次
    if (_this.PromiseState === 'pending') {
      // 1、修改对象的状态 PromiseState
      _this.PromiseState = 'rejected'
      // 2、设置对象结果值 PromiseResult
      _this.PromiseResult = data
      // 3、执行器为异步任务时，调用失败的回调函数，回调函数异步执行
      setTimeout(() => {
        _this.callback.rejectedFn.forEach(item => {
          item(data)
        })
      })
    }
  }

  // 处理抛出异常改变状态的情况
  try {
    // 执行器同步调用
    executor(resolve, reject)
  } catch (e) {
    // 修改promise状态
    reject(e)
  }
}

/**
 * promise then方法：返回一个promise
 * 1、处理执行器为同步任务时的回调
 * 2、处理执行器为异步任务时的回调
 *
 * 3、处理同一种状态指定多个回调的情况
 *
 * 4、处理执行器为同步任务时，then方法的返回结果
 * 5、处理执行器为异步任务时，then方法的返回结果
 *
 * 6、异常穿透，值传递
 * 7、回调函数异步执行
 * @param onResolved
 * @param onRejected
 * @returns {Promise}
 */
Promise.prototype.then = function (onResolved, onRejected) {
  // 处理then方法第二个参数不传的情况（异常穿透）
  if (typeof onRejected !== 'function') {
    onRejected = reason => {
      throw reason
    }
  }

  // 处理then方法第一个不传的情况（值传递）
  if (typeof onResolved !== 'function') {
    onResolved = value => {
      return value
    }
  }

  // 处理then方法的返回结果
  return new Promise((resolve, reject) => {
    const _this = this

    // 处理回调
    function handleCallback(type) {
      try {
        // 获取回调函数的执行结果
        const res = type(_this.PromiseResult)
        if (res instanceof Promise) {
          // 如果回调函数返回的是Promise对象
          res.then(v => {
            resolve(v)
          }, r => {
            reject(r)
          })
        } else {
          // 如果回调函数返回的是结果为成功状态的一般对象
          resolve(res)
        }
      } catch (e) {
        reject(e)
      }
    }

    // 执行器为同步任务时
    // promise的状态为成功
    if (this.PromiseState === 'fulfilled') {
      // 回调函数异步执行
      setTimeout(() => {
        handleCallback(onResolved)
      })
    }

    // 执行器为同步任务时
    // promise的状态为失败
    if (this.PromiseState === 'rejected') {
      // 回调函数异步执行
      setTimeout(() => {
        handleCallback(onRejected)
      })
    }

    // 执行器为异步任务时
    if (this.PromiseState === 'pending') {
      // 保存回调函数
      // 处理同一种状态指定多个回调的情况，用数组收集

      // 收集成功的回调
      this.callback.resolvedFn.push(function () {
        handleCallback(onResolved)
      })

      // 收集失败的回调
      this.callback.rejectedFn.push(function () {
        handleCallback(onRejected)
      })
    }

  })
}

/**
 * then()的语法糖, 相当于: then(undefined, onRejected)
 * @param onRejected
 */
Promise.prototype.catch = function (onRejected) {
  this.then(undefined, onRejected)
}

/**
 * 返回一个成功/失败的promise
 * @param value
 * @returns {Promise}
 */
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    if (value instanceof Promise) {
      value.then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    } else {
      resolve(value)
    }
  })
}

/**
 * 返回一个失败的promise
 * @param reason
 * @returns {Promise}
 */
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason)
  })
}

/**
 * 返回一个新的 promise,
 * 只有所有的 promise 都成功才成功, 成果的结果为所有promise的结果；
 * 只要有一个失败了就直接失败，失败的结果为失败的那个promise返回的结果
 * @param promiseArr
 * @returns {Promise}
 */
Promise.all = function (promiseArr) {
  return new Promise((resolve, reject) => {
    // 记录成功的promise的个数
    let successCount = 0
    // 存储成功的promise的结果
    let result = []

    for (let i = 0; i < promiseArr.length; i++) {
      promiseArr[i].then(v => {
        // promise执行成功，计数+1
        successCount++
        result[i] = v
        // 所有的promise都成功，才执行resolve
        if (successCount === promiseArr.length) {
          resolve(result)
        }
      }, r => {
        // 有一个promise失败，直接执行reject
        reject(r)
      })
    }
  })
}

/**
 * 返回一个新的 promise,
 * 第一个完成的 promise 的状态和结果就是最终的状态和结果
 * @param promiseArr
 * @returns {Promise}
 */
Promise.race = function (promiseArr) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promiseArr.length; i++) {
      // 多个promise之间赛跑，谁快就返回谁
      promiseArr[i].then(v => {
        resolve(v)
      }, r => {
        reject(r)
      })
    }
  })
}